<template>
  <el-form
    ref="ruleFormRef"
    :model="formData"
    @submit.prevent
  >
    <el-row>
      <el-col
        v-for="(item, index) in formItemList"
        :key="item.prop"
        :span="item.span"
      >
        <el-form-item
          :label="item.label"
          :prop="item.prop"
          v-bind="item.formItem"
          :style="{ marginBottom: index > lastRowFristIndex ? '0' : '18px' }"
        >
          <TuDateRange
            v-if="item.type === 'DateRange'"
            ref="dateRangeRef"
            :search-item="item"
            @range-change="rangeChange"
          />
          <TuNumberRange
            v-else-if="item.type === 'NumberRange'"
            ref="numberRangeRef"
            :search-item="item"
            @range-change="rangeChange"
          />
          <component
            v-else
            :is="'Tu' + item.type"
            v-model="formData[item.prop]"
            v-bind="item.itemAttrs"
            v-on="item.events"
            :search-item="item"
          />
        </el-form-item>
      </el-col>
      <el-col
        :span="defaultOption.span"
        :offset="btnOffset"
        class="tu-but-box"
      >
        <el-button
          :icon="Search"
          type="primary"
          @click="searchClick(false)"
        >
          查询
        </el-button>
        <el-button
          :icon="Refresh"
          @click="resetForm(ruleFormRef)"
        >
          重置
        </el-button>
      </el-col>
    </el-row>
  </el-form>
</template>

<script lang='ts' setup>
import { onUnmounted, reactive, ref, watch } from 'vue';
import type { SearchItemType, SearchOptionType } from '../TableType';
import TuInput from './components/TuInput.vue';
import TuSelect from './components/TuSelect.vue';
import TuDatePicker from './components/TuDatePicker.vue';
import TuCascader from './components/TuCascader.vue';
import TuCheckbox from './components/TuCheckbox.vue';
import TuAutocomplete from './components/TuAutocomplete.vue';
import TuInputNumber from './components/TuInputNumber.vue';
import TuRadio from './components/TuRadio.vue';
import TuTreeSelect from './components/TuTreeSelect.vue';
import TuDateTimePicker from './components/TuDateTimePicker.vue';
import TuDateRange from './components/TuDateRange.vue';
import TuNumberRange from './components/TuNumberRange.vue';
import { Search, Refresh } from '@element-plus/icons-vue'
import type { FormInstance } from 'element-plus';

// 当前支持的组件
defineOptions({
  components: {
    'TuInput': TuInput,
    'TuSelect': TuSelect,
    "TuDatePicker": TuDatePicker,
    "TuCascader": TuCascader,
    "TuCheckbox": TuCheckbox,
    "TuAutocomplete": TuAutocomplete,
    "TuInputNumber": TuInputNumber,
    "TuRadio": TuRadio,
    "TuTreeSelect": TuTreeSelect,
    "TuDateTimePicker": TuDateTimePicker,
    "TuDateRange": TuDateRange,
    "TuNumberRange": TuNumberRange
  }
})

const props = withDefaults(defineProps<{
  searchList?: SearchItemType[]
  searchOption?: SearchOptionType
}>(), {
  searchList: () => [],
  searchOption: () => ({ immediate: true, heidden: true })
})

const emits = defineEmits<{
  (e: 'searchClick', isReset: boolean): void
}>()

// 表单对象
const ruleFormRef = ref()

// 默认配置
const defaultOption = reactive({
  span: 6,
  labelWidth: '120px'
})

// 表单对象
const formData = ref<{ [x: string]: any }>({})

// 搜索组件列表
const formItemList = ref<SearchItemType[]>([])

/**
 * 处理表单默认值
 * @param item 单个表单对象
 */
const disposeDefaultValue = (item: SearchItemType): any => {
  if (item?.defaultValue === undefined) {
    if (
      (item.type === 'Select' && item?.itemAttrs?.multiple)
      || (item.type === 'Cascader' && item?.itemAttrs?.props?.multiple)
      || (item.type === 'Checkbox')
      || (item.type === 'TreeSelect' && item?.itemAttrs?.multiple)
    ) {
      // 多选组件默认值
      return []
    } else {
      return null
    }
  } else {
    return item?.defaultValue
  }
}

/**
 * 合并 formItem 属性
 * @param option 配置
 */
const mergeFormItem = (option: any) => {
  if (option) {
    return {
      ...option,
      labelWidth: option?.labelWidth || defaultOption.labelWidth
    }
  } else {
    return {
      labelWidth: defaultOption.labelWidth
    }
  }
}

/**
 * 处理传入的数据
 */
const disposeSearchItem = () => {
  formItemList.value = props.searchList.filter(item => {
    return item?.heidden !== false
  }).map(item => {
    return {
      label: item.label,
      prop: item.prop,
      type: item.type,
      defaultValue: disposeDefaultValue(item),
      options: item?.options || [],
      span: item?.span || defaultOption.span,
      heidden: item?.heidden || true,
      itemAttrs: item?.itemAttrs || {},
      formItem: mergeFormItem(item?.formItem),
      events: item?.events || {}
    }
  })
}

disposeSearchItem()

// 表单绑定对象赋默认值
formItemList.value.forEach(item => {
  if (item.type === 'DateRange' || item.type === 'NumberRange') {
    const propNameArr = item.prop.split(',')
    if (propNameArr.length === 2) {
      formData.value[propNameArr[0]] = item.defaultValue?.[0] || null
      formData.value[propNameArr[1]] = item.defaultValue?.[1] || null
    }
  } else {
    formData.value[item.prop] = item.defaultValue
  }
})

// 搜索按钮和查询按钮的偏移树
const btnOffset = ref(0)
// 倒数第二行最后一个组件的下标
const lastRowFristIndex = ref(formItemList.value.length)

/**
 * 设置按钮初始偏移量
 */
const initBtnOffset = () => {
  // 当前行已用占比
  let rowSpan = 0
  // 当前行最后一个组件的下表
  let lastRowIndex = 0

  for (let i = 0; i < formItemList.value.length; i++) {
    rowSpan += formItemList.value[i]?.span || 0

    if (rowSpan >= 24) {
      rowSpan = 0
      if (rowSpan > 24) {
        i--
      }
      lastRowIndex = i
    }
  }

  if (24 - rowSpan >= defaultOption.span) {
    // 有剩余空间放按钮
    btnOffset.value = 24 - rowSpan - defaultOption.span
    lastRowFristIndex.value = lastRowIndex
  } else {
    // 没有剩余空间放按钮
    btnOffset.value = 24 - defaultOption.span
  }
}

initBtnOffset()

/**
 * 更新自定义范围选择组件值
 * @param dateValue 值
 * @param propName 键
 */
const rangeChange = (dateValue: string[], propName: string) => {
  const propNameArr = propName.split(',')
  if (propNameArr.length === 2) {
    formData.value[propNameArr[0]] = dateValue[0] || null
    formData.value[propNameArr[1]] = dateValue[1] || null
  }
}

/**
 * 更新搜索组件宽度占比
 * @param span 搜索组件单个占比
 */
const upDateItemSpan = (span: number) => {
  if (span === defaultOption.span) return
  defaultOption.span = span
  // 重新排列组件
  disposeSearchItem()
  // 重新设置搜索按钮的位置
  initBtnOffset()
}

// 监听搜索表单长度
const unwatch = watch(() => formItemList.value.length, () => {
  // 更新搜索按钮位置
  initBtnOffset()
})

/**
 * 执行搜索
 * @param isReset 是否重置触发
 */
const searchClick = (isReset: boolean = false) => {
  emits('searchClick', isReset)
}

// 日期范围输入框
const dateRangeRef = ref()
// 数字范围输入框
const numberRangeRef = ref()

// 重置自定义范围组件
const resetFieldRange = (rangeRef: any, item: SearchItemType) => {
  // 重置表单绑定的属性值
  const propName = item.prop.split(',')
  formData.value[propName[0]] = item?.defaultValue?.[0] || null
  formData.value[propName[1]] = item?.defaultValue?.[1] || null

  // 重置显示的属性值
  if (Array.isArray(rangeRef)) {
    rangeRef.forEach(item => {
      item.resetFields()
    })
  } else {
    rangeRef.resetFields()
  }
}

/**
 * 递归查询当前组件插入的位置
 * @index 搜索组件原下标
 */
const findAddIndex = (index: number) => {
  let upIndex = index - 1

  if (upIndex < 0 || formItemList.value.length === 0) {
    return 0
  } else if (upIndex >= formItemList.value.length) {
    return formItemList.value.length - 1
  } else {
    // 当前组件的上一个组件在页面的下标
    const upSearchIndex = formItemList.value.findIndex(item => item.prop === props.searchList[index - 1].prop)
    if (upSearchIndex !== -1) {
      return upSearchIndex + 1
    } else {
      return findAddIndex(upIndex--)
    }
  }
}

/**
 * 控制搜索组件显示隐藏
 * @prop 搜索组件绑定属性
 * @show 是否显示
 */
const setSearchHidden = (prop: string, show: boolean) => {
  if (show) {
    // searchList 上找到该组件重新插入到 formItemList，并赋默认值
    const searchIndex = formItemList.value.findIndex(item => item.prop === prop)
    if (searchIndex !== -1) return

    const searchItemIndex = props.searchList.findIndex(item => item.prop === prop)
    const addIndex = findAddIndex(searchItemIndex)

    const activeSearchItem = props.searchList[searchItemIndex]

    // 插入页面
    formItemList.value.splice(addIndex, 0, {
      label: activeSearchItem.label,
      prop: activeSearchItem.prop,
      type: activeSearchItem.type,
      defaultValue: disposeDefaultValue(activeSearchItem),
      options: activeSearchItem?.options || [],
      span: activeSearchItem?.span || defaultOption.span,
      heidden: activeSearchItem?.heidden || true,
      itemAttrs: activeSearchItem?.itemAttrs || {},
      formItem: mergeFormItem(activeSearchItem?.formItem),
      events: activeSearchItem?.events || {}
    })

    // 赋默认值
    if (activeSearchItem.type === 'DateRange' || activeSearchItem.type === 'NumberRange') {
      const propNameArr = activeSearchItem.prop.split(',')
      if (propNameArr.length === 2) {
        formData.value[propNameArr[0]] = activeSearchItem.defaultValue?.[0] || null
        formData.value[propNameArr[1]] = activeSearchItem.defaultValue?.[1] || null
      }
    } else {
      formData.value[activeSearchItem.prop] = activeSearchItem?.defaultValue || null
    }
  } else {
    // formItemList 上找到该组件删除，并从 formData 上删除指定属性
    const searchIndex = formItemList.value.findIndex(item => item.prop === prop)
    if (searchIndex === -1) return

    // 移出查询条件
    if (formItemList.value[searchIndex].type === 'DateRange' || formItemList.value[searchIndex].type === 'NumberRange') {
      const propNameArr = formItemList.value[searchIndex].prop.split(',')
      delete formData.value[propNameArr[0]]
      delete formData.value[propNameArr[1]]
    } else {
      delete formData.value[formItemList.value[searchIndex].prop]
    }

    // 删除搜索组件
    formItemList.value.splice(searchIndex, 1)
  }
}

/**
 * 重置搜索表单
 * @param formEl 表单实例
 */
const resetForm = (formEl: FormInstance | undefined) => {
  if (!formEl) return
  formEl.resetFields()

  // 重置自定义组件值
  formItemList.value.forEach(item => {
    switch (item.type) {
      case "DateRange":
        resetFieldRange(dateRangeRef.value, item)
        break;
      case "NumberRange":
        resetFieldRange(numberRangeRef.value, item)
        break;
      default:
        break;
    }
  })

  searchClick(true)
}

/**
 * 设置查询条件
 * @param data 对象
 * @param immediate 设置完后是否执行查询
 * @param isRest 设置前是否重置搜索条件
 */
const setSearchData = (data: any, immediate: boolean = false, isRest: boolean = false) => {
  if (isRest) {
    resetForm(ruleFormRef.value)
  }

  for (const key in data) {
    formData.value[key] = data[key]
  }

  if (immediate) {
    searchClick()
  }
}

/**
 * 设置下拉框数据
 * @param prop 搜索条件绑定的属性名
 * @param list 下拉列表
 */
const setDropDown = (prop: string, list: any[]) => {
  let propIndex = formItemList.value.findIndex(item => item.prop === prop)
  if (propIndex !== -1) {
    formItemList.value[propIndex].options = list
  }
}

onUnmounted(() => {
  unwatch()
})

defineExpose({
  formData,
  upDateItemSpan,
  setSearchHidden,
  setSearchData,
  setDropDown
})
</script>

<style scoped lang='scss'>
.tu-item-margin {
  margin-bottom: 0;
}

.tu-but-box {
  text-align: right;
}
</style>